<?php
/**
 * Модель работы с личными сообщениями пользователям.
 */
class Users_Model_Message extends Users_Model_Abstract {
	/**
	 * @var array
	 */
	protected static $_aMainDbFields = array(
		'id', 'subject', 'body', 'created', 'created_ip', 'created_by', 'target',
	);

	/**
	 * Создание нового сообщения.
	 * 
	 * @param string $sSubject
	 * @param string $sBody
	 * @param integer|Users_Model_User $mTo
	 * @return Users_Model_Message
	 */
	public static function send($sSubject,$sBody,$mTo = 0) {
		if ($mTo instanceof Users_Model_User) {
			$mTo = $mTo->getId();
		}

		if (!is_integer($mTo)) {
			throw new Zend_Exception('Wrong third param for method '.__METHOD__);
		}

		$mTo = $mTo <= 0 ? -1 : $mTo;

		$aFields = array(
			'subject' => (string)$sSubject,
			'body' => (string)$sBody,
			'created_ip' => Zend_Controller_Front::getInstance()->getRequest()->getClientIp(),
			'created_by' => Users_Model_User::getUser()->getId(),
			'target' => $mTo,
		);

		$oTable = new Users_Table_Message();
		$aFields['id'] = $oTable->insert($aFields);
		$aFields['created'] = time();

		return new self($aFields);
	}

	/**
	 * Получение объекта сообщения по его идентификатору.
	 * 
	 * @param integer $iId
	 * @return Users_Model_Message
	 */
	public static function getById($iId) {
		if (1 > $iId = intval($iId)) {
			throw new Zend_Exception('Wrong first param for method '.__METHOD__);
		}

		$oTable = new Users_Table_Message();

		return new self($oTable->fetchRow(array('id = ?' => $iId))->toArray());
	}

	/**
	 * Получение списка сообщений для данного пользователя.
	 * 
	 * @param inetger|Users_Model_User $mTarget
	 * @param boolean $bRead   Флаг отображения прочитанных сообщений.
	 * @param boolean $bDeleted   Флаг отображения удалённых сообщений.
	 * @return Iterator
	 */
	public static function getListByTarget($mTarget,$bRead = false, $bDeleted = false) {
		$mTarget = $mTarget instanceof Users_Model_User ? $mTarget->getId() : intval($mTarget);

		$oTable = new Users_Table_Message();
		$oSelect = $oTable->select();
		$bReadFlagLinked = false;
		$bDeletedFlagLinked = false;

		foreach (array($mTarget,0) as $iTarget) {
			$oSelect->orWhere('target = ?',$iTarget);

			if ($bRead == false) {
				if (!$bReadFlagLinked) {
					$bReadFlagLinked = true;

					$oSelect->joinLeft(
						array('t2' => 't_message_flag'),
						"`t2`.`message_id` = `id` AND `t2`.`user_id` = $mTarget AND `t2`.`flag` = 1",
						array());
				}

				$oSelect->where(new Zend_Db_Expr('`t2`.`flag` IS NULL'));
			}

			if ($bDeleted == false) {
				if (!$bDeletedFlagLinked) {
					$bDeletedFlagLinked = true;

					$oSelect->joinLeft(
						array('t3' => 't_message_flag'),
						"`t3`.`message_id` = `id` AND `t3`.`user_id` = $mTarget AND `t3`.`flag` = 2",
						array());
				}

				$oSelect->where(new Zend_Db_Expr('`t3`.`flag` IS NULL'));
			}
		}

		$oSelect->order('created DESC');
		$oList = new Users_Model_Message_List($oSelect->query()->fetchAll());
		$oList->setObjectClass(__CLASS__);

		return $oList;
	}

	/**
	 * Обработчик условий фильтрации.
	 * 
	 * @param string $sKey
	 * @param string $sRule
	 * @param mixed $mValue
	 * @return array
	 */
	public static function _callbackFilter($sKey,$sRule,$mValue) {
		switch (TRUE) {
			// Поля основной таблицы.
			case in_array($sKey,self::$_aMainDbFields):
				$mCond = is_array($mValue)
					? new Zend_Db_Expr($sKey.($sRule == '<>' ? ' NOT' : '').' IN ('.join(',',$mValue).")")
					: "$sKey $sRule ?";
				$mValue = is_array($mValue) ? null : $mValue;
				break;

			// Ошибка - неправильное название поля.
			default:
				throw new Zend_Exception("Wrong field name '$sKey' in \$aFilter argument (method ".__METHOD__.")");
		}

		return array($mCond,$mValue);
	}

	protected static $_bSelectObjectMode = false;

	/**
	 * Получение списка пользователей.
	 *
	 * @param array $aFilter
	 * @param array $aOrder
	 * @param mixed $mLimit
	 * @return Users_Model_User_Db_List
	 */
	public static function getList($aFilter = array(), $aOrder = array('login' => 'asc'), $mLimit = 0) {
		// Выставление флага необходимости получения Zend_Db_Select объекта а не итератора.
		$bSelectObjectMode = self::$_bSelectObjectMode;
		self::$_bSelectObjectMode = false;

		// Получение Zend_Db_Select объекта с применёнными условиями фильтрации, сортировки и ограничения количества.
		$oSelect = self::_getList(
			new Users_Table_Message(),
			$aFilter,
			$aOrder,
			$mLimit,
			array(__CLASS__,'_callbackFilter')
		);

		// Если установлен режим получения объекта Zend_Db_Select.
		if ($bSelectObjectMode) {
			return $oSelect;
		}
		// Выполнение запроса и возращение объекта со списком результатов.
		else {
			$oList = new Users_Model_Message_List($oSelect->query()->fetchAll());
			$oList->setObjectClass(__CLASS__);
			return $oList;
		}
	}

	/**
	 * Получение количества строк для текущего фильтра.
	 * 
	 * @param array $aFilter
	 * @return integer
	 */
	public static function getCount($aFilter = array()) {
		self::$_bSelectObjectMode = true;
		$oSelect = self::getList($aFilter,array());
		$oTable = $oSelect->getTable();

		$oSelect->reset(Zend_Db_Select::COLUMNS);
		$oSelect->reset(Zend_Db_Select::FROM);
		$oSelect->from($oTable->getTableName(),array('CNT' => new Zend_Db_Expr('COUNT(*)')));

		$mResult = $oSelect->query()->fetch();
		return intval($mResult['CNT']);
	}

	/**
	 * @var array
	 */
	protected $_aFields;

	/**
	 * Инициализация объекта класса.
	 * 
	 * @param array $aFields
	 */
	public function __construct($aFields) {
		$this->_aFields = $aFields;
	}

	/**
	 * Получение идентификатора сообщения.
	 * 
	 * @return integer
	 */
	public function getId() {
		return $this->_aFields['id'];
	}

	/**
	 * Получение заголовка сообщения.
	 * 
	 * @return string
	 */
	public function getSubject() {
		return $this->_aFields['subject'];
	}

	/**
	 * Получение тела сообщения.
	 * 
	 * @return string
	 */
	public function getBody() {
		return $this->_aFields['body'];
	}

	/**
	 * Получение времени создания сообщения.
	 * 
	 * @return integer
	 */
	public function getCreated() {
		return $this->_aFields['created'];
	}

	/**
	 * Получение IP адреса, с которого было отправлено сообщение.
	 * 
	 * @return string
	 */
	public function getCreatedIp() {
		return $this->_aFields['created_ip'];
	}

	/**
	 * Получение идентификатора того, кто создал сообщение.
	 * 
	 * @return integer
	 */
	public function getCreatedBy() {
		return $this->_aFields['created_by'];
	}

	/**
	 * Получение идентификатора получателя, или 0 для широковещательных сообщений.
	 * 
	 * @return integer
	 */
	public function getTarget() {
		return $this->_aFields['target'];
	}
}